//package com.competition.web.admin.service.impl;
//
//import com.admin.param.contract.IUpdateGenereateResult;
//import com.admin.param.contract.IVisitCustomerResult;
//import com.admin.vo.VisitCustomerVO;
//import com.admin.vo.contract.IStaffInfoVO;
//import com.basic.service.impl.BaseServiceImpl;
//import com.common.util.ArrayDifference;
//import com.common.util.CopyEntity;
//import com.common.util.SecureRandomUtil;
//import com.common.util.WithdrawalOfSurplus;
//import com.competition.web.admin.mapper.StaffMapper;
//import com.competition.web.admin.service.IStaffService;
//import com.competition.web.constant.RedisConstant;
//import com.competition.web.entity.Staff;
//import com.competition.web.entity.VisitCustomer;
//import com.unify.type.NumberOfEmployeeOrdersDispatched;
//
//import java.security.SecureRandom;
//import java.util.ArrayList;
//import java.util.Arrays;
//import java.util.HashMap;
//import java.util.HashSet;
//import java.util.Iterator;
//import java.util.LinkedHashMap;
//import java.util.LinkedHashSet;
//import java.util.List;
//import java.util.Map;
//import java.util.Random;
//import java.util.Set;
//import java.util.concurrent.TimeUnit;
//import java.util.function.Function;
//import java.util.stream.Collectors;
//import java.util.stream.Stream;
//
//import javax.annotation.Resource;
//
//import org.springframework.data.redis.core.Cursor;
//import org.springframework.data.redis.core.HashOperations;
//import org.springframework.data.redis.core.RedisTemplate;
//import org.springframework.data.redis.core.ScanOptions;
//import org.springframework.data.redis.core.ValueOperations;
//import org.springframework.stereotype.Service;
//
//@Service
//public class StaffServiceImpl extends BaseServiceImpl<Staff> implements IStaffService {
//
//	private RedisTemplate<String, Object> redisTemplate;
//
//	@Resource
//	public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
//		this.redisTemplate = redisTemplate;
//	}
//
//	public StaffServiceImpl(StaffMapper mapper) {
//		super(mapper);
//	}
//
//	protected void insertPropteris(Staff data) {
//		long time = System.currentTimeMillis() / 1000;
//		data.setCreateTime(time);
//		data.setUpdateTime(time);
//	}
//
//	public int insert(Staff data) {
//
//		int res = super.insert(data);
//
//		redisTemplate.delete(RedisConstant.getLeavekey());
//
//		redisTemplate.delete(RedisConstant.getLeaveToNormal());
//
//		return res;
//	}
//
//	protected void updatePropteris(Staff data) {
//		data.setUpdateTime(System.currentTimeMillis() / 1000);
//	}
//
//	protected Class<Staff> getEntityClass() {
//		return Staff.class;
//	}
//
//	@Override
//	protected String checkData(Staff data) {
//
//		Long departStartTime = data.getLeaveStart();
//
//		Long departEndTime = data.getLeaveEnd();
//
//		Long currentTime = System.currentTimeMillis();
//
//		if (departStartTime < currentTime && currentTime < departEndTime) {
//			// 再请假期间范围
//			data.setStatus(((byte) 1));
//		} else {
//			data.setStatus(((byte) 0));
//		}
//
//		data.setLeaveStart(departStartTime / 1000);
//
//		data.setLeaveEnd(departEndTime / 1000);
//
//		return "";
//	}
//
//	@Override
//	public <VO extends IStaffInfoVO> Map<String, VO> getStaff(String[] staffNames, Class<VO> target) {
//
//		Map<String, VO> map = new HashMap<>();
//		if (0 == staffNames.length) {
//			return map;
//		}
//
//		StaffMapper mapper = this.getBaseMapper();
//
//		List<Staff> staffs = mapper.getStaffs(staffNames);
//
//		VO staffInfoVO;
//
//		for (Staff staff : staffs) {
//
//			staffInfoVO = CopyEntity.copyEntity(staff, target);
//
//			map.put(staff.getStaffName(), staffInfoVO);
//		}
//
//		return map;
//	}
//
//	@Override
//	public List<Staff> staffsByLeaveTask(int start, Long currentTime, Long endTime) {
//
//		StaffMapper staffMapper = this.getBaseMapper();
//
//		return staffMapper.parseLeaveTask(currentTime / 1000, endTime / 1000, start, 100);
//	}
//
//	/**
//	 * 更新状态
//	 * 
//	 * @param staffs
//	 */
//	public void updateStatus(List<Staff> staffs, Long currentTime, byte status) {
//
//		List<Staff> list = new ArrayList<>();
//
//		Long start, end;
//
//		Staff update;
//
//		for (Staff staff : staffs) {
//
//			start = staff.getLeaveStart() * 1000;
//
//			end = staff.getLeaveEnd() * 1000;
//
//			if (start <= currentTime && currentTime <= end) {
//
//				update = new Staff();
//
//				update.setId(staff.getId());
//
//				update.setStatus(status);
//
//				// 再请假期间范围
//				list.add(update);
//			}
//		}
//
//		if (0 == list.size()) {
//			return;
//		}
//
//		StaffMapper staffMapper = this.getBaseMapper();
//
//		staffMapper.updateStatus(list.stream().toArray(Staff[]::new));
//
//	}
//
//	@Override
//	public int countByLeaveToCache(long leaveStart, long leaveEnd) {
//
//		String key = RedisConstant.getLeavekey();
//
//		ValueOperations<String, Object> valueOperations = this.redisTemplate.opsForValue();
//
//		Integer number = (Integer) valueOperations.get(key);
//		//
//		if (null != number) {
//			return number;
//		}
//
//		StaffMapper staffMapper = this.getBaseMapper();
//
//		number = staffMapper.countByLeave(leaveStart / 1000, leaveEnd / 1000);
//
//		if (null == number) {
//			valueOperations.set(key, number, 3, TimeUnit.SECONDS);
//
//			return 0;
//		}
//
//		valueOperations.set(key, number, 6, TimeUnit.MINUTES);
//
//		return number;
//	}
//
//	@Override
//	public List<Staff> parseLeaveToNormal(int start, Long currentTime, Long endTime) {
//
//		StaffMapper staffMapper = this.getBaseMapper();
//
//		return staffMapper.parseLeaveToNormal(currentTime / 1000, endTime / 1000, start, 100);
//	}
//
//	@Override
//	public Integer countByLeaveToNormal(long leaveStart, long leaveEnd) {
//
//		String key = RedisConstant.getLeaveToNormal();
//
//		ValueOperations<String, Object> valueOperations = this.redisTemplate.opsForValue();
//
//		Integer number = (Integer) valueOperations.get(key);
//		//
//		if (null != number) {
//			return number;
//		}
//
//		StaffMapper staffMapper = this.getBaseMapper();
//
//		number = staffMapper.countByLeaveToNormal(leaveStart / 1000, leaveEnd / 1000);
//
//		if (null == number) {
//			valueOperations.set(key, number, 3, TimeUnit.SECONDS);
//
//			return 0;
//		}
//
//		valueOperations.set(key, number, 6, TimeUnit.MINUTES);
//
//		return number;
//	}
//
//	/**
//	 * 判断值在不在数组里面
//	 * 
//	 * @param elementData
//	 * @param o
//	 * @return
//	 */
//	public int indexOf(Integer[] elementData, Integer o) {
//
//		int size = elementData.length;
//
//		if (o == null) {
//			for (int i = 0; i < size; i++)
//				if (elementData[i] == null)
//					return i;
//		} else {
//			for (int i = 0; i < size; i++)
//				if (o.equals(elementData[i]))
//					return i;
//		}
//		return -1;
//	}
//
//	public boolean contains(Integer[] elementData, Integer o) {
//		return indexOf(elementData, o) >= 0;
//	}
//
//	/**
//	 * 
//	 * @param elementData 原数组
//	 * @param o           过滤数组
//	 * @return 第一个为 null 的 索引
//	 */
//	public int remove(Integer[] elementData, Integer[] c) {
//
//		int r = 0, w = 0;
//
//		int size = elementData.length;
//
//		boolean modified = false;
//		try {
//			for (; r < size; r++)
//				if (this.contains(c, elementData[r]) == false)
//					elementData[w++] = elementData[r];
//		} finally {
//			// Preserve behavioral compatibility with AbstractCollection,
//			// even if c.contains() throws.
//			if (r != size) {
//				System.arraycopy(elementData, r, elementData, w, size - r);
//				w += size - r;
//			}
//			if (w != size) {
//				// clear to let GC do its work
//				for (int i = w; i < size; i++)
//					elementData[i] = null;
//				size = w;
//				modified = true;
//			}
//
//		}
//
//		return modified ? w : -1;
//
//	}
//
//	public Integer[] deleteValueByNull(Integer[] elementData) {
//
//		int index = 0;
//
//		for (int i = 0; i < elementData.length; i++) {
//
//			if (null == elementData[i]) {
//				index = i;
//				break;
//			}
//
//		}
//
//		Integer[] integers = new Integer[index];
//
//		System.arraycopy(elementData, 0, integers, 0, index);
//
//		return integers;
//	}
//
//	/**
//	 * 随机取ids
//	 * 
//	 * @param ids
//	 * @param size      选几个
//	 * @param assignIds 要排除的
//	 */
//	protected Integer[] randomlySelectIds(Integer[] ids, int size, Integer[] assignIds) {
//
//		ids = removeAssignIds(ids, assignIds);
//
//		if (ids.length > size) {
//			// 从索引中任意选取 size 个
//			ids = SecureRandomUtil.getRundomNumber(ids, size);
//		} else if (ids.length < size) {
//			throw new Error("选择的员工太少");
//		}
//
//		return ids;
//	}
//	
//	/**
//	 * 去掉指派的
//	 * @return
//	 */
//	private Integer[] removeAssignIds(Integer[] ids, Integer [] assignIds) {
//		
//		if (null != assignIds && 0 != assignIds.length) {
//
//			int index = this.remove(ids, assignIds);
//
//			if (-1 != index) {
//
//				Integer[] res = new Integer[index];
//
//				System.arraycopy(ids, 0, res, 0, index);
//
//				ids = res;
//			}
//
//		}
//		
//		return ids;
//		
//	}
//	
//
//	@Override
//	public <VO> List<VO> getStaffInfoByIds(Integer[] ids, Class<VO> voClass, int size, Integer[] assignIds) {
//
//		ids = randomlySelectIds(ids, size, assignIds);
//
//		if (0 == ids.length) {
//			return new ArrayList<VO>();
//		}
//
//		return this.getDataByIds(ids, voClass);
//	}
//
//	/**
//	 * 
//	 * if (null == noonIds || 0 == noonIds.length) {
//	 * 
//	 * // 走正常 逻辑 lists.add(this.getStaffInfoByIds(noone, voClass,
//	 * noonAndAfternoonSize[0], assignIds)); } else {
//	 * 
//	 * Integer[] receiveIds = evenlyDistributedProcessing(noonIds, noone,
//	 * noonAndAfternoonSize[0], assignIds);
//	 * 
//	 * if (0 == receiveIds.length) {
//	 * 
//	 * // 走正常逻辑
//	 * 
//	 * lists.add(this.getStaffInfoByIds(noone, voClass, noonAndAfternoonSize[0],
//	 * assignIds)); } else { // 平分逻辑 lists.add(this.getDataByIds(receiveIds,
//	 * voClass)); } }
//	 * 
//	 * if (null != afteronneIds && 0 != afteronneIds.length) {
//	 * 
//	 * // 走正常 逻辑 lists.add(this.getStaffInfoByIds(afteronneIds, voClass,
//	 * noonAndAfternoonSize[1], assignIds)); } else { // 走平分逻辑
//	 * 
//	 * Integer[] receiveIds = evenlyDistributedProcessing(afternoonIds,
//	 * afteronneIds, noonAndAfternoonSize[1], assignIds);
//	 * 
//	 * if (0 == receiveIds.length) { // 走正常逻辑
//	 * lists.add(this.getStaffInfoByIds(afteronneIds, voClass,
//	 * noonAndAfternoonSize[0], assignIds)); } else { // 平分逻辑
//	 * lists.add(this.getDataByIds(receiveIds, voClass)); }
//	 * 
//	 * }
//	 */
//	@Override
//	public <VO> List<List<VO>> getStaffInfoByIds(IVisitCustomerResult customerResult, Class<VO> voClass,
//			Integer[] noonAndAfternoonSize, Integer[][] assignIds) {
//
//		List<List<VO>> lists = new ArrayList<List<VO>>();
//
//		Integer[] noone = customerResult.getIds();
//
//		Integer[] afteronneIds = customerResult.getAfternoons();
//
//		// 判断是否走平分逻辑
//
//		HashOperations<String, String, Number> hashOperations = redisTemplate.opsForHash();
//
//		Number res = hashOperations.get(RedisConstant.STATISTICS_DAY, "day");
//
//		long day = res == null ? 0 : res.longValue();
//
//		int[] noonIds = null;
//
//		int[] afternoonIds;
//
//		// TODO
//		if (day >= 7) {
//
//			// 走平分逻辑
//
//			Cursor<Map.Entry<String, Number>> cursor = hashOperations.scan(RedisConstant.STATISTICS_VISIT,
//					ScanOptions.scanOptions().count(500).build());
//
//			Map.Entry<String, Number> entry;
//
//			List<NumberOfEmployeeOrdersDispatched> staffNumberOfAllocationsNoons = new ArrayList<NumberOfEmployeeOrdersDispatched>();
//
//			List<NumberOfEmployeeOrdersDispatched> staffNumberOfAllocationsAfternoons = new ArrayList<NumberOfEmployeeOrdersDispatched>();
//
//			String[] key;
//
//			NumberOfEmployeeOrdersDispatched employeeOrdersDispatched;
//
//			while (cursor.hasNext()) {
//
//				entry = cursor.next();
//
//				key = entry.getKey().split("-");
//
//				employeeOrdersDispatched = new NumberOfEmployeeOrdersDispatched();
//
//				employeeOrdersDispatched.setId(Integer.valueOf(key[1]));
//
//				employeeOrdersDispatched.setNumber(entry.getValue().intValue());
//
//				if (key[0].equals("a")) {
//					// 上午
//					staffNumberOfAllocationsNoons.add(employeeOrdersDispatched);
//				} else {
//					staffNumberOfAllocationsAfternoons.add(employeeOrdersDispatched);
//				}
//			}
//
//			// 对比 上午数量 若相差不多 则跳过上午处理
//
//			noonIds = this.pairwiseComparison(staffNumberOfAllocationsNoons);
//
//			afternoonIds = this.pairwiseComparison(staffNumberOfAllocationsAfternoons);
//
//			// 两两对比每一个人 如果比别人少2单
//
//			// 对比 下午数量 若相差不多 则跳过下午处理
//
//			// 对比 上午
//
//			// 对比 下午
//
//			selectCondition(lists, noonIds, noone, voClass, noonAndAfternoonSize[0], assignIds[0]);
//
//			selectCondition(lists, afternoonIds, afteronneIds, voClass, noonAndAfternoonSize[1], assignIds[1]);
//
//		} else {
//
//			lists.add(this.getStaffInfoByIds(noone, voClass, noonAndAfternoonSize[0], assignIds[0]));
//
//			lists.add(this.getStaffInfoByIds(afteronneIds, voClass, noonAndAfternoonSize[1], assignIds[1]));
//		}
////
//		return lists;
//	}
//
//	/**
//	 * 选择走哪一个逻辑
//	 * 
//	 * @param <VO>
//	 * @param lists                结果集
//	 * @param noonIds              上午或下午相差较多需要平衡的员工 id
//	 * @param noone                上午或下午选择派单的员工
//	 * @param voClass
//	 * @param visitSize 需要拜访客户的员工的数量
//	 * @param assignIds            指派的员工 id 数组
//	 */
//	private <VO> void selectCondition(List<List<VO>> lists, int[] noonIds, Integer[] noone, Class<VO> voClass,
//			int visitSize, Integer[] assignIds) {
//
//		if (null == noonIds || 0 == noonIds.length) {
//
//			// 走正常 逻辑
//			lists.add(this.getStaffInfoByIds(noone, voClass, visitSize, assignIds));
//
//			return;
//		}
//
//		Integer[] receiveIds = evenlyDistributedProcessing(noonIds, noone, visitSize, assignIds);
//
//		if (0 == receiveIds.length) {
//
//			// 走正常逻辑
//
//			lists.add(this.getStaffInfoByIds(noone, voClass, visitSize, assignIds));
//
//			return;
//
//		}
//		// 平分逻辑
//		
//		List<VO> dataByIds = this.getDataByIds(receiveIds, voClass);
//		
//		if (dataByIds.size() != visitSize ) {
//			throw new Error("员工数量与所需要的员工数量不一致");
//		}
//		
//		lists.add(dataByIds);
//	}
//
//	/**
//	 * 均摊处理
//	 * 
//	 * @param noonIds              上午或下午 要平衡的 员工id
//	 * @param noone                上午或下午选择的员工
//	 * @param noonAndAfternoonSize 上午或下午 需要拜访客户的员工的数量
//	 * @param assignIds            需要排除的 id
//	 */
//	protected Integer[] evenlyDistributedProcessing(int[] noonIds, Integer[] noone, int noonAndAfternoonSize,
//			Integer[] assignIds) {
//
//
//		// 走平分逻辑
//
//		// 求交集，看看选的人里面有没有 平分逻辑里面的
//
//		Integer[] resIds = ArrayDifference.intConvertInteger(ArrayDifference.getIntersection(noone, noonIds));
//
//		if (0 == resIds.length) { // 选的人里面没有 平分逻辑里面的
//			// 走正常 逻辑
////			lists.add(this.getStaffInfoByIds(noone, voClass, noonAndAfternoonSize[0], assignIds));
//			return new Integer[0];
//		}
//
//		// 已排好序的
//		// 平分逻辑的人 去掉指派的
//		resIds = removeAssignIds(resIds, assignIds);
//		
//		Integer[] reallyIds = new Integer[noonAndAfternoonSize];
//		
//		if (noonAndAfternoonSize <= resIds.length) {
//			// 平分逻辑的人 够用了
//			// 取 前 noonAndAfternoonSize 个
//			System.arraycopy(resIds, 0, reallyIds, 0, noonAndAfternoonSize);
//			
//			return reallyIds;
//		}
//		
//
//		// 求差集
//		Integer[] excludeIdsReceive = ArrayDifference.intConvertInteger(ArrayDifference.getDifference(noone, noonIds));
//		
//		// 平分逻辑的人 不够用
//
//		// 选的人里面有 平分逻辑里面的
//
////		Integer[] excludeIdsReceive = excludeIds.stream().map(e -> e.intValue()).toArray(Integer[]::new);
//		// 不在平分逻辑中的 走随机读取
//		excludeIdsReceive = randomlySelectIds(excludeIdsReceive, noonAndAfternoonSize - resIds.length , assignIds);
//
//		int j = 0;
//		for (int i = 0; i < resIds.length; i++) {
//
//			reallyIds[j++] = resIds[i];
//		}
//
//		for (int i = 0; i < excludeIdsReceive.length; i++) {
//
//			reallyIds[j++] = excludeIdsReceive[i];
//		}
//
//		return reallyIds;
//	}
//	
//
//	/**
//	 * <pre>
//	 * <font>两两对比每一个人 如果比别人少2单 则记录 id</font>
//	 * </pre>
//	 * 
//	 * @param staffNumberOfAllocationsNoons
//	 */
//	protected int[] pairwiseComparison(List<NumberOfEmployeeOrdersDispatched> employeeOrdersDispatcheds) {
//
//		// TODO
//
//		NumberOfEmployeeOrdersDispatched[] dispatcheds = employeeOrdersDispatcheds
//				.toArray(new NumberOfEmployeeOrdersDispatched[employeeOrdersDispatcheds.size()]);
//
////		外层
//		NumberOfEmployeeOrdersDispatched outer;
//
////		内层
//		NumberOfEmployeeOrdersDispatched innerLayers;
//
//		int diff;
//
//		// 需要派单的
//
//		int j = 0;
//		
//		
//		int len = dispatcheds.length;
//		
//		//  存储数量差距超过2的 并以数量进行排序
//		List<NumberOfEmployeeOrdersDispatched> list = new ArrayList<NumberOfEmployeeOrdersDispatched>();
//		
//
//		for (int i = 0; i < len - 1; i++) {
//
//			outer = dispatcheds[i];
//
//			for (j = i + 1; j < len; j ++) {
//
//				innerLayers = dispatcheds[j];
//
//				diff = outer.getNumber() - innerLayers.getNumber();
//				
//				if (2 <= diff) {
//
//					list.add(innerLayers);
//
////					System.out.println("k >=: " + k);
//				} else if (diff <= -2) {
//					
//					list.add(outer);
//				}
//			}
//		}
//
//		
//		list.sort((f,second) ->second.getNumber() -f.getNumber());
//		
//		// 保持排序去重
//		int[] res = new LinkedHashSet<>(list).stream().mapToInt(e->e.getId()).toArray();
//		
//		return res;
//	}
//
//	@Override
//	protected Staff getEntityInstance() {
//		// TODO Auto-generated method stub
//		return new Staff();
//	}
//
//	@Override
//	public <VO> List<Staff> getStaffsFromCache(List<VO> assignIds, List<Function<VO, Integer>> functions) {
//
//		Stream<VO> stream;
//
//		Set<Integer> integers = new HashSet<Integer>();
//
//		for (Function<VO, Integer> function : functions) {
//
//			stream = assignIds.stream();
//
//			integers.addAll(stream.map(e -> function.apply(e)).collect(Collectors.toSet()));
//		}
//
//		Integer[] ids = integers.stream().toArray(Integer[]::new);
//
//		return this.getStaffs(ids);
//	}
//
//	public List<Staff> getStaffs(Integer[] ids) {
//
//		if (0 == ids.length) {
//			return new ArrayList<Staff>(0);
//		}
//
//		String key = RedisConstant.getStaffsKey(ids);
//
//		ValueOperations<String, Object> valueOperations = this.redisTemplate.opsForValue();
//
//		List<Staff> number = (List<Staff>) valueOperations.get(key);
//		//
//		if (null != number) {
//			return number;
//		}
//
//		StaffMapper staffMapper = this.getBaseMapper();
//
//		number = staffMapper.getDataByIds(ids);
//
//		if (null == number) {
//
//			number = new ArrayList<Staff>(0);
//
//			valueOperations.set(key, number, 3, TimeUnit.SECONDS);
//
//			return number;
//		}
//
//		valueOperations.set(key, number, 6, TimeUnit.MINUTES);
//
//		return number;
//	}
//
//	@Override
//	public <VO> List<VO> getStaffInfoByIds(IUpdateGenereateResult[] genereateResults, Class<VO> voClass) {
//
//		Integer[] ids = new Integer[genereateResults.length];
//
//		for (int i = 0; i < genereateResults.length; i++) {
//
//			ids[i] = genereateResults[i].getUserId();
//		}
//
//		return entityConvertToVo(this.getStaffs(ids), voClass);
//	}
//
//	@Override
//	public <VO extends IStaffInfoVO> List<VO> getStaffNames(String[] names, Class<VO> target) {
//
//		StaffMapper staffMapper = this.getBaseMapper();
//
//		return entityConvertToVo(staffMapper.getStaffByNames(names), target);
//
//	}
//}